home *** CD-ROM | disk | FTP | other *** search
/ Windows Expert / Windows Expert.iso / windownt / sossnt.zip / SOSSNT / SRC / FILES.C < prev    next >
C/C++ Source or Header  |  1993-03-05  |  32KB  |  1,183 lines

  1. /*
  2.  *  files.c --
  3.  *      File manipulation procedures.  This module is highly machine
  4.  *      dependent.
  5.  *
  6.  *  Author:
  7.  *      See-Mong Tan
  8.  *  Modified by:
  9.  *    Rich Braun @ Kronos
  10.  *
  11.  *  Revision history:
  12.  *  
  13.  * $Log: files.c_v $
  14.  * Revision 1.6  1991/05/13  17:43:50  richb
  15.  * Correct the return value of file_freeblocks so it won't produce
  16.  * an error if there are 0 free blocks.
  17.  *
  18.  * Revision 1.5  1991/04/17  18:04:30  richb
  19.  * Correct the modification time stored when a file block is
  20.  * written.  (small bug in 3.1.)
  21.  *
  22.  * Revision 1.4  1991/04/11  20:36:51  richb
  23.  * Add name truncation support.
  24.  *
  25.  * Revision 1.3  1991/03/15  22:39:19  richb
  26.  * Several mods:  fixed unlink and rename.
  27.  *
  28.  */
  29.  
  30. #ifdef RCSID
  31. static char _rcsid_ = "$Id: files.c_v 1.6 1991/05/13 17:43:50 richb Exp $";
  32. #endif
  33.  
  34. #include "common.h"
  35. #include <direct.h>        /* for dos directory ops */
  36. #include <fcntl.h>        /* these ... */
  37. #include <sys/stat.h>        /* for ... */
  38. #include <io.h>            /* low level DOS access */
  39. #include <sys/types.h>
  40. #include <sys/utime.h>
  41.  
  42. /* Default permissions for files are 555 for read-only and 777  */
  43. /* for writeable.  The low-order 9 bits can be modified by the  */
  44. /* administrator.                        */
  45. u_short uperm_rdonly = UPERM_FILE | UPERM_READ | UPERM_EXEC;
  46. u_short uperm_write  = UPERM_FILE | UPERM_READ | UPERM_WRITE | UPERM_EXEC;
  47. u_short uperm_dir    = UPERM_DIR | UPERM_READ | UPERM_WRITE | UPERM_SEARCH;
  48.  
  49. #ifdef NOVELL
  50. #include "novell.h"        /* Novell definitions */
  51. static struct _uidmap {
  52.     u_long    unix_ID;
  53.     u_long    Novell_ID;
  54.     } *uIDmappings = NULL;
  55. static int uIDcount;
  56. static u_long uIDoffset;
  57. static u_long gID;
  58. static u_short novelldirprot;
  59.  
  60. static bool_t ldnovell (u_long, char *, struct nfsfattr *);
  61. #endif /* NOVELL */
  62.  
  63. #ifdef DOSAUTH
  64. /* Support for handling file authentication */
  65. struct _authent {
  66.     u_short    uid;        /* UID of file owner */
  67.     u_short gid;        /* GID of file owner */
  68.     u_short mode;        /* Protection mode bits */
  69.     u_short reserved;
  70.     };
  71. #define AUTHSIZE (sizeof (struct _authent))
  72. #define AUTHFILE "AUTHS.DMP"
  73. static int authfh = 0;
  74. #endif /* DOSAUTH */
  75.  
  76. static int file_nsubdirs(char *);
  77. static bool_t file_readattr(char *, struct nfsfattr *);
  78. static void   cvtd2uattr (u_long, struct _finddata_t *, struct nfsfattr *);
  79.  
  80. #define DRIVE_SCALINGFACTOR 4   /* scaling factor for NT */
  81.  
  82. BOOL
  83. setnormalfileattr(char *name)
  84. {
  85.     return SetFileAttributes(name,FILE_ATTRIBUTE_NORMAL);
  86. }
  87.  
  88. BOOL
  89. setreadonlyfileattr(char *name)
  90. {
  91.     return SetFileAttributes(name,FILE_ATTRIBUTE_READONLY);
  92. }
  93.  
  94. /*
  95.  *  bool_t file_getattr(char *path, struct nfsfattr *attr) --
  96.  *      Gets attributes for designated file or directory and puts
  97.  *      the information in *attr.  Returns TRUE if successful, FALSE otherwise.
  98.  */
  99. bool_t file_getattr(path, attr)
  100.     char *path;
  101.     struct nfsfattr *attr;
  102. {
  103.     if (path == NULL)
  104.       return FALSE;
  105.  
  106.     /* See if info is cached in the inode tree */
  107.  
  108. #ifdef CACHEIT
  109.     if (inattrget (pntoin (path), attr) != NULL)
  110.     return TRUE;
  111. #endif
  112.  
  113.     /* Else go out to disk */
  114. DBGPRT1 (inode, "getattr going to disk, path = %s", path);
  115.     return  file_readattr(path, attr);
  116. }
  117.  
  118. /* myfindfirst - note that _findclose is called, so that the search */
  119. /* cannot be continued.  This only returns the first file match. */
  120. int
  121. myfindfirst(path, findbuf)
  122. char *path;
  123. struct _finddata_t *findbuf;
  124. {
  125.     long fhand;
  126.  
  127.     fhand = _findfirst(path,findbuf);
  128.     if ( fhand < 0 ) {
  129.         DBGPRT0 (inode, "myfindfirst, fhand<0");
  130.         return -1;
  131.     }
  132.     /* We used to check only for NORMAL/SUBDIR/RDONLY files, but that */
  133.     /* didn't seem to work right, and besides, it seems like we should */
  134.     /* just see most files, right? */
  135.     DBGPRT3 (inode, "myfindfirst  name=%s attrib=0x%x  access=%d",path,findbuf->attrib,_access(path,04));
  136.     _findclose(fhand);
  137.     return 0;
  138. }
  139.  
  140.  
  141. /*
  142.  *  bool_t file_readattr(char *path, struct nfsfattr *attr) --
  143.  *      Reads file attributes for a file from disk.
  144.  *      Returns TRUE if successful, FALSE otherwise.
  145.  *    Adds file to directory tree if the file does not already exist in
  146.  *    the tree.
  147.  */
  148. static bool_t file_readattr(path, attr)
  149.     char *path;
  150.     struct nfsfattr *attr;
  151. {
  152.     struct _finddata_t findbuf;
  153.     u_long nodeid;
  154.  
  155.     /* Special-case the root directory */
  156.     if (strlen (path) == 2 && path[1] == ':') {
  157.  
  158.     (void) bzero((char*)attr, sizeof(struct nfsfattr));
  159.     attr->na_blocksize = NFS_MAXDATA;
  160.  
  161. #ifdef OLDSTUFF
  162.     char   npath [10];
  163.     DBGPRT1 (inode, "Special for root = %s", path);
  164.     /* Get attributes of volume label */
  165.     sprintf (npath, "%s\\*.*", path);
  166.     if (myfindfirst(path, &findbuf) == 0) {
  167.  
  168.         /* Load attributes from findbuf */
  169.         cvtd2uattr (nodeid, &findbuf, attr);
  170.     }
  171. #endif
  172.  
  173.     /* Set directory attributes */
  174.     attr->na_type = NFDIR;
  175.     attr->na_mode = uperm_dir;
  176.     attr->na_nlink = 2;
  177.     attr->na_blocks = 1;         /* just say 1 block */
  178.     attr->na_size = 1024;
  179.  
  180.     /* cache this info */
  181.     inattrset (nodeid, attr);
  182.     return TRUE;
  183.     }
  184.  
  185.     /* Look for the file given */
  186. DBGPRT1 (inode, "caling myfindfirst for path= %s", path);
  187.     if (myfindfirst(path,&findbuf) != 0) {
  188.  
  189.     /* not successful */
  190.     if ((nodeid = pntoin(path)) != -1)
  191.       inremnode (nodeid);
  192. DBGPRT0 (inode, "return false A");
  193.     return FALSE;
  194.     }
  195.     if ((nodeid = pntoin(path)) == -1) {
  196.       nodeid = addpathtodirtree(path);
  197.     }
  198.  
  199.     /* Load attributes from findbuf */
  200.     (void) bzero((char*)attr, sizeof(struct nfsfattr));
  201.     cvtd2uattr (nodeid, &findbuf, attr);
  202.  
  203.         if (findbuf.attrib & _A_SUBDIR)
  204.       attr->na_mode = uperm_dir;
  205.         else if (findbuf.attrib & _A_RDONLY)
  206.       attr->na_mode = uperm_rdonly;
  207.     else
  208.       attr->na_mode = uperm_write;
  209.  
  210. #ifdef NOVELL
  211.     /* Novell stuff */
  212.     (void) ldnovell (nodeid, path+2, attr);
  213. #endif
  214. #ifdef DOSAUTH
  215.     /* Read authentication entry */
  216.     if (authfh != 0 && lseek (authfh, nodeid * AUTHSIZE, SEEK_SET) ==
  217.       nodeid * AUTHSIZE) {
  218.         struct _authent authentry;
  219.         if (read (authfh, &authentry, AUTHSIZE) == AUTHSIZE) {
  220.         attr->na_uid = authentry.uid;
  221.         attr->na_gid = authentry.gid;
  222.         attr->na_mode = authentry.mode;
  223.         }
  224.     }
  225. #endif /* DOSAUTH */
  226.     /* cache this info */
  227.     inattrset (nodeid, attr);
  228. DBGPRT0 (inode, "return true A");
  229.     return TRUE;
  230. }
  231.  
  232. static void cvtd2uattr (nodeid, findbuf, attr)
  233.      u_long nodeid;
  234.      struct _finddata_t *findbuf;
  235.      struct nfsfattr *attr;
  236. {
  237.     /* file protection bits and type */
  238.     if (findbuf->attrib & _A_SUBDIR) {           /* subdirectory */
  239.     attr->na_type = NFDIR;
  240.     attr->na_nlink = 2;  /*** + file_nsubdirs(path) ***/
  241.     /* # of subdirectories plus this one */
  242.     }
  243.     else if (findbuf->attrib & _A_RDONLY) {        /* rdonly */
  244.     attr->na_type = NFREG;
  245.     attr->na_nlink = 1;
  246.     }
  247.     else {
  248.     attr->na_type = NFREG;          /* normal file */
  249.     attr->na_nlink = 1;
  250.     }
  251.  
  252.     /* file size in bytes */
  253.     if (findbuf->attrib & _A_SUBDIR) {        /* directory */
  254.     attr->na_blocks = 1;         /* just say 1 block */
  255.     attr->na_size = 1024;
  256.     }
  257.     else {
  258.     attr->na_size = findbuf->size;
  259.     attr->na_blocks = findbuf->size / BASIC_BLOCKSIZE + 
  260.       (findbuf->size % BASIC_BLOCKSIZE == 0 ? 0 : 1);
  261.     }
  262.     /* preferred transfer size in blocks */
  263.     attr->na_blocksize = NFS_MAXDATA;
  264.  
  265.     /* device # == drive # */
  266.     attr->na_fsid = ingetfsid (nodeid);
  267.     attr->na_rdev = attr->na_fsid;
  268.  
  269.     /* inode # */
  270.     attr->na_nodeid = nodeid;
  271.  
  272.     /* time of last access */
  273.     attr->na_atime.tv_usec = 0;
  274.     attr->na_atime.tv_sec = findbuf->time_write;
  275.  
  276.     /* time of last write */
  277.     attr->na_mtime = attr->na_atime;       /* note all times are the same */
  278.  
  279.     /* time of last change */
  280.     attr->na_ctime = attr->na_atime;
  281. }
  282.  
  283. #ifdef NOVELL
  284. /*
  285.  *  u_char novell_GDH (int fsid) --
  286.  *    Get Novell directory handle for a filesystem.
  287.  */
  288. u_char novell_GDH (fsid)
  289. int fsid;
  290. {
  291. union REGS regsin, regsout;
  292.  
  293.     /* Get the file system's directory handle */
  294.     regsin.x.ax = 0xE900;
  295.     regsin.x.dx = fsid - 1;
  296.     intdos (®sin, ®sout);
  297.  
  298.     /* Return -1 error code if the permanent directory bit is not set or */
  299.     /* the local-directory bit is set.                          */
  300.     if ((regsout.h.ah & 0x83) != 1)
  301.       return 255;
  302.  
  303.     return regsout.h.al;
  304. }
  305.  
  306. /*
  307.  *  void ldnovell (u_long nodeid, char *path, struct nfsfattr *attr) --
  308.  *    Loads attributes of a Novell network file
  309.  */
  310. static bool_t ldnovell (nodeid, path, attr)
  311.      u_long nodeid;
  312.      char   *path;
  313.      struct nfsfattr *attr;
  314. {
  315.     FILE *fp, *fopen();
  316.     int i;
  317.     int stat;
  318.     u_char handle;
  319.     char fcn [10];
  320.     union REGS regsin, regsout;
  321.     struct SREGS segregs;
  322.  
  323.     if ((handle = novell_GDH (ingetfsid (nodeid))) == 255)
  324.     return FALSE;
  325.  
  326.     /* Initialize the Novell ID mapping table if not set */
  327.     if (uIDmappings == NULL) {
  328.     uIDmappings = (struct _uidmap *) malloc (sizeof (struct _uidmap) *
  329.                         MAXNOVELLID);
  330.     if (uIDmappings == NULL) {
  331.         fprintf (stderr, "out of memory\n");
  332.         abort();
  333.     }
  334.     uIDoffset = uIDcount = gID = 0;
  335.  
  336.     /* Default protection is 775 */
  337.     novelldirprot = UPERM_OWNER | UPERM_GROUP | UPERM_READ | UPERM_SEARCH;
  338.  
  339.     if ((fp = fopen(IDFILE, "r")) == NULL) {
  340.         fprintf (stderr, ">>> File %s missing\n", IDFILE);
  341.     }
  342.     else {
  343.         while(fscanf(fp, "%s", fcn) != EOF) {
  344.         /* Check command line for 'offset', 'group', 'user', */
  345.         /* 'protection'.                     */
  346.         if (fcn[0] == 'o')
  347.             fscanf(fp, "%ld", &uIDoffset);
  348.         else if (fcn[0] == 'g')
  349.             fscanf(fp, "%ld", &gID);
  350.         else if (fcn[0] == 'p')
  351.             fscanf(fp, "%o", &novelldirprot);
  352.         else if (fcn[0] == 'u') {
  353.             char user[20];
  354.             fscanf(fp, "%s %ld %ld", user,
  355.                &uIDmappings[uIDcount].unix_ID,
  356.                &uIDmappings[uIDcount].Novell_ID);
  357.             if (uIDcount < MAXNOVELLID-1)
  358.               uIDcount++;
  359.         }
  360.         }
  361.         fclose (fp);
  362.     }
  363.     }
  364.  
  365.     segregs.ds = get_ds();
  366.     segregs.es = segregs.ds;
  367.  
  368.     if (attr->na_type != NFDIR) {
  369.     /* Set up the Scan File Information request block, as defined on */
  370.     /* page 283 of the Novell API Reference, rev 1.00.         */
  371.  
  372.     static struct _sfireq sfireq =     /* These are placed in static */
  373.       {0, 0x0F, -1, -1, 0, 0, 0};    /* memory because code here   */
  374.     static struct _sfirep sfirep;    /* assumes seg register DS.   */
  375.  
  376.     sfireq.handle = handle;
  377.     sfireq.pathlen = strlen (path);
  378.     sfireq.len = 6 + sfireq.pathlen;
  379.     sfirep.len = sizeof (sfirep) -2;
  380.     strcpy (sfireq.path, path);
  381.  
  382.     novell_API(0xE3, &sfireq, &sfirep, regsin, ®sout, &segregs);
  383.     if (regsout.h.al != 0) {
  384.         DBGPRT2 (nfsdebug, "%s sfi err %d", path, regsout.h.al);
  385.         return FALSE;
  386.     }
  387.     attr->na_uid = sfirep.info.ownerID;
  388.     attr->na_gid = gID;
  389.     }
  390.     else {
  391.     /* Special case for directories:  invoke Scan Directory For   */
  392.     /* Trustees system call, defined on p. 280 of Novell API Ref. */
  393.  
  394.     /* Load the protection bits */
  395.     attr->na_mode = UPERM_DIR | novelldirprot;
  396. #if 0
  397.     /* SDFT not supported because Novell allows a directory to be */
  398.     /* a member of several groups while Unix only attaches one    */
  399.     /* group ID to the file.  We punt and just return the same    */
  400.     /* group every time, to avoid confusion.              */
  401.  
  402.     static struct _sdftreq sdftreq = {0, 0x0C, 0, 0, 0};
  403.     static struct _sdftrep sdftrep;
  404.  
  405.     sdftreq.handle = handle;
  406.     sdftreq.pathlen = strlen (path);
  407.     sdftreq.len = 4 + sdftreq.pathlen;
  408.     sdftrep.len = sizeof (sdftrep) -2;
  409.     strcpy (sdftreq.path, path);
  410.  
  411.     novell_API (0xE2, &sdftreq, &sdftrep, regsin, ®sout, &segregs);
  412.     if (regsout.h.al == 0) {
  413.         attr->na_uid = sdftrep.ownerID;
  414.     }
  415.     else
  416. #endif /* 0 */
  417.     {
  418.         /* If SDFT call failed, usually due to access problems, */
  419.         /* use the Scan Directory Info call.            */
  420.         static struct _sdireq sdireq = {0, 0x02, 0, 0, 0};
  421.         static struct _sdirep sdirep;
  422.  
  423.         sdireq.handle = handle;
  424.         sdireq.pathlen = strlen (path);
  425.         sdireq.len = 5 + sdireq.pathlen;
  426.         sdirep.len = sizeof (sdirep) -2;
  427.         strcpy (sdireq.path, path);
  428.  
  429.         novell_API (0xE2, &sdireq, &sdirep, regsin, ®sout, &segregs);
  430.         DBGPRT3 (nfsdebug, "SDIREQ %d: %d %ld", sdireq.handle, regsout.h.al,
  431.              sdirep.ownerID);
  432.         if (regsout.h.al != 0)
  433.           return FALSE;
  434.         attr->na_uid = sdirep.ownerID;
  435.         attr->na_gid = gID;
  436.     }
  437.     }
  438.  
  439.     DBGPRT2 (nfslookup, "%s ID = %ld", path, attr->na_uid);
  440.  
  441.     /* Look for ID in mapping table */
  442.     for (i = 0; i < uIDcount; i++)
  443.       if (uIDmappings[i].Novell_ID == attr->na_uid) {
  444.       attr->na_uid = uIDmappings[i].unix_ID;
  445.       return TRUE;
  446.       }
  447.  
  448.     /* Not found in mapping table:  add the offset and return. */
  449.     attr->na_uid += uIDoffset;
  450.     return TRUE;
  451. }
  452. #endif /* NOVELL */
  453.  
  454. /*
  455.  *  int file_nsubdirs(char *path) --
  456.  *    Returns # of subdirectories in the given directory.
  457.  */
  458. static int file_nsubdirs(path)
  459.     char *path;
  460. {
  461.     int subdirs = 0;
  462. #define VALID(ft) (strcmp((ft).name, ".") != 0 && strcmp((ft).name, "..") != 0)
  463.  
  464. /* Hack:  this routine eats a lot of time and doesn't work anyway. */
  465.  
  466. printf("FILE_NSUBDIRS IS RETURNING 0 - A LIEEEEEEE!!!!\n");
  467. return 0;
  468.  
  469. #if 0
  470.     struct _finddata_t ft;
  471.     char name[MAXPATHNAMELEN];
  472.  
  473.     (void) strcpy(name, path);
  474.     (void) strcat(name, "\\*.*");        /* append wildcard */
  475.  
  476.  
  477. /* NOTE: NOT UPGRADED TO WINDOWS NT, SINCE THIS IS COMMENTED OUT */
  478.  
  479.     if (_dos_findfirst(name, _A_SUBDIR, &ft) != 0)
  480.         if (VALID(ft))
  481.             subdirs++;
  482.         else
  483.             return 0;
  484.  
  485.     while(_dos_findnext(&ft) == 0)
  486.         if (VALID(ft))
  487.             subdirs++;
  488.     DBGPRT2 (nfslookup, "dos_findfirst '%s', found %d subdirs",
  489.         name, subdirs);
  490.  
  491.     /* IF THIS CODE IS RESURRECTED, BE SURE TO CALL _findclose() !! */
  492.  
  493.     return subdirs;
  494. #endif /* 0 */
  495.  
  496. #undef VALID
  497. }
  498.  
  499. /*
  500.  *  int file_freeblocks(int drive, long *free, long *total) --
  501.  *      Return # of free blocks in specified filesystem (ie. drive).
  502.  */
  503. long file_freeblocks(drive, free, total)
  504.     int drive;
  505.     long *free, *total;
  506. {
  507.     char drvname[8];
  508.     DWORD nsectors, nbytes, nfreeclusters, nclusters;
  509.  
  510.     sprintf(drvname,"%c:\\",'A'+drive-1);
  511.     if ( GetDiskFreeSpace(drvname,&nsectors,&nbytes,
  512.             &nfreeclusters,&nclusters) == FALSE ) {
  513.         (void) fprintf(stderr, "freeblocks: err, cannot read\n");
  514.         return -1;
  515.     }
  516. /*    DBGPRT2 (nfsdebug, "%c: blocks free %ld", 'A'+drive-1,
  517.          (long) nfreeclustors * nsectors); */
  518.  
  519.     *free = ((long)nfreeclusters * nsectors) / DRIVE_SCALINGFACTOR;
  520.     *total = ((long)nclusters * (long)nsectors) / DRIVE_SCALINGFACTOR;
  521.  
  522.     return 0;
  523. }
  524.  
  525. /* a file pointer cache for read requests */
  526. #define FRDCSIZ 10
  527. static struct {
  528.     u_long nodeid;
  529.     FILE *fp;
  530. } frdc_cache[FRDCSIZ];
  531.  
  532. static int frdc_last;        /* last location saved */
  533.  
  534. /*
  535.  *  void frdc_save(u_long nodeid, FILE *fp) --
  536.  *    Cache read file pointers.
  537.  */
  538. static void frdc_save(nodeid, fp)
  539.      u_long nodeid;
  540.      FILE *fp;
  541. {
  542.     if (frdc_cache[frdc_last].fp != NULL)
  543.         (void) fclose(frdc_cache[frdc_last].fp);      /* throw away */
  544.     frdc_cache[frdc_last].nodeid = nodeid;
  545.     frdc_cache[frdc_last++].fp = fp;
  546.     if (frdc_last == FRDCSIZ)
  547.         frdc_last = 0;
  548. }
  549.  
  550. /*
  551.  *  void frdc_del(u_long nodeid) --
  552.  *    Delete saved file pointer from read cache.  No effect if file
  553.  *    was not cached.  Closes file pointer also.
  554.  */
  555. static void frdc_del(nodeid)
  556.      u_long nodeid;
  557. {
  558.     int i;
  559.  
  560.     for(i = 0; i < FRDCSIZ; i++) {
  561.     if (frdc_cache[i].fp != NULL && frdc_cache[i].nodeid == nodeid) {
  562.         (void) fclose(frdc_cache[i].fp);
  563.         frdc_cache[i].fp = NULL;
  564.         return;
  565.     }
  566.     }
  567. }
  568.  
  569. /*
  570.  *  FILE *frdc_find(u_long nodeid) --
  571.  *    Finds cached file pointer corresponding to nodeid, or NULL
  572.  *    if no such file exists.
  573.  */
  574. FILE *frdc_find(nodeid)
  575.      u_long nodeid;
  576. {
  577.     int i;
  578.  
  579.     for(i = 0; i < FRDCSIZ; i++) {
  580.     if (frdc_cache[i].fp != NULL && frdc_cache[i].nodeid == nodeid)
  581.       return frdc_cache[i].fp;
  582.     }
  583.  
  584.     return NULL;
  585. }
  586.  
  587. /*
  588.  *  int file_read(u_long nodeid, u_long offset,
  589.  *                u_long count, char *buffer) --
  590.  *    Reads count bytes at offset into buffer.  Returns # of bytes read,
  591.  *      and -1 if an error occurs, or 0 for EOF or null file.
  592.  */
  593. int file_read(nodeid, offset, count, buffer)
  594.      u_long nodeid;
  595.      u_long offset, count;
  596.      char *buffer;
  597. {
  598.     FILE *fp;
  599.     bool_t saved = FALSE;
  600.     int bytes = 0;
  601.     char path [MAXPATHNAMELEN];
  602.  
  603.     if ((fp = frdc_find(nodeid)) != NULL) {
  604.     saved = TRUE;
  605.     }
  606.     else if ((fp = fopen(intopn (nodeid, path), "rb")) == NULL) {
  607.       DBGPRT3 (nfserr, "file_read open errno=%d path=%s nodeid=%d", errno,path,nodeid);
  608.       return -1;
  609.      }
  610.  
  611.     /* Seek to correct position */
  612.     if (fseek(fp, (long) offset, 0) != 0) {
  613.     if (!feof(fp)) {
  614.         (void) fclose(fp);
  615.         DBGPRT1 (nfserr, "file_read unable to seek? path=%s", path);
  616.         return -1;
  617.     }
  618.     else
  619.       return 0;
  620.     }
  621.  
  622.     /* Read from the file */
  623.     bytes = fread(buffer, sizeof(char), (size_t) count, fp);
  624.     if (!saved)
  625.       frdc_save(nodeid, fp);
  626.  
  627.     return bytes;
  628. }
  629.  
  630. /*
  631.  *  int file_rddir(u_long nodeid, u_long offs, struct udirect *udp) --
  632.  *      Put file information at offs in directory at path in nfs cookie 
  633.  *    at *udp. Returns # of bytes in record, 0 if there are no more entries
  634.  *       or -1 for a read error.
  635.  */
  636. int file_rddir(nodeid, offs, udp)
  637.      u_long nodeid;
  638.      u_long offs;
  639.      struct udirect *udp;
  640. {
  641.     char filename[MAXPATHNAMELEN];
  642.     char npath[MAXPATHNAMELEN], path[MAXPATHNAMELEN];
  643.     struct _finddata_t findbuf;
  644.     struct nfsfattr attr;
  645.     u_long fnode;
  646.     long fhand;
  647.  
  648. #define SUD  32 /*    sizeof(struct udirect) */ /* full udp cookie size */
  649.  
  650.     if (offs == 0) {
  651.     /* Force a read of the full directory if offset is zero. */
  652.  
  653.     if (intopn (nodeid, path) == NULL)
  654.       return -1;
  655.  
  656.     /* look for the first file in the directory */
  657.     (void) sprintf(npath, "%s\\*.*", path);
  658.  
  659.     if ( (fhand=_findfirst(npath, &findbuf)) >= 0) {
  660.  
  661.         /* Read file attributes from each entry into inode cache */
  662.         for (;;) {
  663.  
  664.         /* convert to lowercase and get the full path */
  665.         (void) strtolower(findbuf.name);
  666.         (void) sprintf(filename, "%s\\%s", path, findbuf.name);
  667.  
  668.         if ((fnode = pntoin(filename)) == -1)
  669.           fnode = addpathtodirtree(filename);
  670.         if (inattrget (fnode, &attr) == (struct nfsfattr *) NULL)
  671.           (void) bzero ((char*)&attr, sizeof (struct nfsfattr));
  672.         cvtd2uattr (fnode, &findbuf, &attr);
  673.         if (findbuf.attrib & _A_SUBDIR)
  674.           attr.na_mode = uperm_dir;
  675.         else if (findbuf.attrib & _A_RDONLY)
  676.           attr.na_mode = uperm_rdonly;
  677.         else
  678.           attr.na_mode = uperm_write;
  679. #ifdef NOVELL
  680.         (void) ldnovell (fnode, filename+2, &attr);
  681. #endif
  682.         /* cache this info */
  683.         inattrset (fnode, &attr);
  684.  
  685.         /* fetch next entry */
  686.         if (_findnext(fhand,&findbuf) != 0) {
  687.           break;
  688.         }
  689.         }
  690.         _findclose(fhand);
  691.     }
  692.     }
  693.  
  694.     /* fetch the proper inode */
  695.     if ((udp->d_fileno = ingetentry (nodeid, offs / SUD, udp->d_name)) == -1)
  696.       return -1;
  697.  
  698.     /* store the remaining udp info */
  699.     udp->d_namlen = strlen(udp->d_name);
  700.     udp->d_offset = offs + SUD;
  701.     udp->d_reclen = UDIRSIZ(udp);
  702.  
  703.     /* return 0 if this is the last entry */
  704.     if (ingetentry (nodeid, (offs / SUD) + 1, filename) == -1)
  705.       return 0;
  706.     else
  707.       return udp->d_reclen;
  708.  
  709. #undef SUD
  710. }
  711.     
  712. /*
  713.  *  char *strtolower(char *s) --
  714.  *    Converts all characters in s to lower case.  Returns s.
  715.  */
  716. char *strtolower(s)
  717.     char *s;
  718. {
  719.     char *tmp;
  720.  
  721.     tmp = s;
  722.     while(*s != '\0') {
  723.         if (isalpha(*s) && isupper(*s))
  724.             *s = tolower(*s);
  725.         s++; 
  726.     }
  727.  
  728.     return tmp;
  729. }
  730.  
  731. /*
  732.  *  enum nfsstat file_write(u_long nodeid, u_long offset,
  733.  *                          u_long count, char *buffer) --
  734.  *      Write to file with name at offset, count bytes of data from buffer.
  735.  *    File should already exist.  Returns 0 for success, or some error 
  736.  *    code if not.
  737.  */
  738. enum nfsstat file_write(nodeid, offset, count, buffer)
  739.     u_long nodeid;
  740.     u_long offset;
  741.     u_long count;
  742.     char *buffer;
  743. {
  744.     int handle;            /* write file handle */
  745.     long newoff;
  746.     char name [MAXPATHNAMELEN];
  747.     int fw_num = WR_SIZ;
  748.     struct nfsfattr attr;
  749.     time_t now;
  750.  
  751.     if (intopn (nodeid, name) == NULL)
  752.       return NFSERR_STALE;
  753.  
  754.     frdc_del(nodeid);            /* delete from read cache */
  755.  
  756.     /* Get cached file attributes */
  757.     if (inattrget (nodeid, &attr) == (struct nfsfattr *) NULL) {
  758.         fprintf (stderr, "file_write: attrget failed\n");
  759.     }
  760.     else {
  761.         /* If the file is read-only, temporarily set it to read/write */
  762.         if (!(attr.na_mode & UCHK_WR))
  763.           (void) setnormalfileattr(name);
  764.     }
  765.  
  766.     /* open for writing only */
  767.     handle = open(name, O_WRONLY | O_BINARY);
  768.     if (handle == -1)
  769.         return puterrno(errno);    /* return error code */
  770.  
  771.     DBGPRT4 (nfswrite, "%s, %ld bytes at %ld (len = %ld)",
  772.          name, count, offset, filelength (handle));
  773.  
  774.     newoff = lseek(handle, offset, 0);
  775.     if (count < WR_SIZ) fw_num = count;
  776.     if (write(handle, buffer, fw_num) == -1) {
  777.         (void) close(handle);
  778.         return puterrno(errno);        /* some error */
  779.     }
  780.  
  781.     /* Update cached file attributes */
  782.     attr.na_size = filelength (handle);
  783.     (void) time (&now);
  784.     attr.na_atime.tv_usec = 0;
  785.     attr.na_atime.tv_sec = now;
  786.     attr.na_mtime = attr.na_atime;
  787.     attr.na_ctime = attr.na_atime;
  788.     (void) inattrset (nodeid, &attr);
  789.  
  790.     (void) close(handle);
  791.     
  792.     /* If the file is read-only, set its _A_RDONLY attribute */
  793.     if (!(attr.na_mode & UCHK_WR))
  794.       (void) setreadonlyfileattr(name);
  795.     return NFS_OK;
  796. }
  797.  
  798. /*
  799.  *  enum nfsstat file_create(char *name, struct nfssattr *sattr,
  800.  *                           struct nfsfattr *fattr)
  801.  *      Creates a file with full path name and attributes sattr, and returns
  802.  *      the file attributes in *fattr.  Adds file to directory tree.
  803.  *      Returns NFS_OK for success, or some error code for failure.
  804.  */
  805. enum nfsstat file_create(name, sattr, fattr)
  806.      char *name;
  807.      struct nfssattr *sattr;
  808.      struct nfsfattr *fattr;
  809. {
  810.     int handle;            /* file handle */
  811.     enum nfsstat stat;
  812.     u_long node;
  813.     int sattribs = S_IREAD;        /* set attributes */
  814.  
  815.     if (name == NULL)
  816.       return NFSERR_NOENT;
  817.  
  818.     if ((stat = validate_path (name)) != NFS_OK)
  819.       return (stat);
  820.  
  821.     if (sattr->sa_mode & UCHK_WR)       /* file is writeable */
  822.       sattribs |= S_IWRITE;       /* set DOS file to be read & write */
  823.  
  824.     /* Remove the inode if assigned */
  825.     if ((node = pntoin (name)) != -1) {
  826.     frdc_del (node);
  827.     inremnode (node);
  828.     }
  829.  
  830. #if 0
  831.  
  832.     /* obsolete code -- now get uid/gid from RPC header */
  833.     if (sattr->sa_uid == -1 || sattr->sa_gid == -1) {
  834.     char parent [MAXPATHNAMELEN];
  835.     struct nfsfattr pattr;        /* attributes of parent */
  836.     char *strrchr();
  837.  
  838.     /* Set up UID and GID defaults from parent inode */
  839.     strcpy (parent, name);
  840.     *strrchr (parent, '\\') = '\0';
  841.     if (!file_getattr (parent, &pattr)) {
  842.         DBGPRT1 (nfsdebug, "no attrs %s", parent);
  843.     }
  844.     else {
  845.         if (sattr->sa_uid == -1)
  846.           sattr->sa_uid = pattr.na_uid;
  847.         if (sattr->sa_gid == -1)
  848.           sattr->sa_uid = pattr.na_gid;
  849.     }
  850.     }
  851. #endif
  852.  
  853.     DBGPRT4 (nfsdebug, "file_create %s <%o> [%ld,%ld]", name,
  854.          (int) sattr->sa_mode, sattr->sa_uid, sattr->sa_gid);
  855.  
  856.     /* check if file already exists */
  857.     if ((handle = open(name, O_CREAT | O_TRUNC, sattribs)) == -1)
  858.       return puterrno (errno);
  859.     close(handle);
  860.  
  861.     /* Add to inode tree */
  862.     if ((node = pntoin(name)) == -1)
  863.       node = addpathtodirtree(name);
  864.  
  865.     /* Set the file's ownership */
  866.     (void) file_setowner (node, sattr->sa_uid, sattr->sa_gid);
  867.  
  868.     /* Read the file's attributes and return */
  869.     if (! file_readattr(name, fattr)) 
  870.       return NFSERR_IO;      /* just created but not found now! */
  871.  
  872.     return NFS_OK;
  873. }
  874.  
  875. /*
  876.  *  int file_setperm(char *path, long perm) --
  877.  *      Sets file permissions depending on perm.  Perm is of two types,
  878.  *      uperm_write (regular file) or uperm_rdonly (read only).
  879.  *    Returns 0 for success or some error code if an error occurs.
  880.  */
  881. enum nfsstat file_setperm(nodeid, perm)
  882.      u_long nodeid;
  883.      long perm;
  884. {
  885.     int stat;
  886.     char path [MAXPATHNAMELEN];
  887.     struct nfsfattr attr;
  888.  
  889.     if (intopn(nodeid, path) == NULL)    /* get file name */
  890.       return NFSERR_STALE;
  891.  
  892. #ifndef DOSAUTH
  893.     if (perm & UPERM_WRITE) {
  894.     stat = setnormalfileattr(path);
  895.     perm = uperm_write;
  896.     }
  897.     else {
  898.     stat = setreadonlyfileattr(path);
  899.     perm = uperm_rdonly;
  900.     }
  901. #endif
  902.  
  903.     if (stat == TRUE) {
  904.     /* Update cached file attributes */
  905.     if (inattrget (nodeid, &attr) != (struct nfsfattr *) NULL) {
  906.         attr.na_mode = perm;
  907.         (void) inattrset (nodeid, &attr);
  908.     }
  909.     return NFS_OK;
  910.     } else
  911.       return puterrno(errno);
  912. }    
  913.         
  914. /*
  915.  *  int file_setsize(u_long nodeid, long size) --
  916.  *      Sets file size.
  917.  *    Returns 0 for success or some error code if an error occurs.
  918.  */
  919. enum nfsstat file_setsize(nodeid, size)
  920.      u_long nodeid;
  921.      long size;
  922. {
  923.     int handle;
  924.     char path [MAXPATHNAMELEN];
  925.     struct nfsfattr attr;
  926.  
  927.     if (intopn(nodeid, path) == NULL)    /* get file name */
  928.       return NFSERR_STALE;
  929.  
  930.     if (size == 0L) {
  931.     if ((handle = open(path, O_CREAT | O_TRUNC, S_IWRITE)) == -1)
  932.         return puterrno (errno);
  933.     close(handle);
  934.  
  935.     /* Update cached file attributes */
  936.     if (inattrget (nodeid, &attr) != (struct nfsfattr *) NULL) {
  937.         attr.na_size = 0;
  938.         (void) inattrset (nodeid, &attr);
  939.     }
  940.     return NFS_OK;
  941.     }
  942.     else
  943.       return NFSERR_IO;
  944. }    
  945.  
  946. /*
  947.  *  int file_settime(u_long nodeid, long secs) --
  948.  *      Sets file time specified by secs (# of seconds since 0000, Jan 1, 1970.
  949.  *    Returns 0 for success or some error code if an error occurs.
  950.  */
  951. enum nfsstat file_settime(nodeid, secs)
  952.      u_long nodeid;
  953.      long secs;
  954. {
  955.     int stat;
  956.     char path [MAXPATHNAMELEN];
  957.     struct nfsfattr attr;
  958.     struct _utimbuf ut;
  959.  
  960. printf("FILE_SETTIME called\n");
  961.     if (intopn(nodeid, path) == NULL)    /* get file name */
  962.       return NFSERR_STALE;
  963.  
  964.     ut.actime = ut.modtime = secs;
  965.     stat = _utime(path, &ut);
  966.  
  967.     if (stat != 0)
  968.       return puterrno(errno);
  969.     else {
  970.     /* Update cached file attributes */
  971.     if (inattrget (nodeid, &attr) != (struct nfsfattr *) NULL) {
  972.         attr.na_atime.tv_usec = 0;
  973.         attr.na_atime.tv_sec = secs;
  974.         attr.na_mtime = attr.na_atime;
  975.         attr.na_ctime = attr.na_atime;
  976.         (void) inattrset (nodeid, &attr);
  977.     }
  978.  
  979.     return NFS_OK;
  980.     }
  981. }
  982.  
  983. /*
  984.  *  int file_setowner(u_long nodeid, long uid, long gid) --
  985.  *      Sets file ownership values.
  986.  *      This can only set the values in cache, because DOS doesn't
  987.  *    support an on-disk representation.
  988.  */
  989. enum nfsstat file_setowner(nodeid, uid, gid)
  990.      u_long nodeid;
  991.      long uid, gid;
  992. {
  993.     struct nfsfattr attr;
  994.     char path [MAXPATHNAMELEN];
  995.  
  996.     if (intopn (nodeid, path) == NULL)
  997.       return NFSERR_NOENT;
  998.     DBGPRT3 (nfsdebug, "Setting owner to [%ld,%ld] %s", uid, gid, path);
  999.  
  1000.     if (file_getattr (path, &attr)) {
  1001. #ifdef NOVELL
  1002.     if (!(attr.na_mode & UPERM_DIR) && uid != -1) {
  1003.         /* Set up the Scan File Information request block, as defined on */
  1004.         /* page 283 of the Novell API Reference, rev 1.00.         */
  1005.  
  1006.         static struct _sfireq sfireq = /* These are placed in static */
  1007.           {0, 0x0F, -1, -1, 0, 0, 0};  /* memory because code here   */
  1008.         static struct _sfirep sfirep;  /* assumes seg register DS.   */
  1009.         static struct _setfireq setfireq =
  1010.           {0, 0x10, 0};
  1011.         static struct _setfirep setfirep;
  1012.         u_char handle;
  1013.         union REGS regsin, regsout;
  1014.         struct SREGS segregs;
  1015.         int i;
  1016.  
  1017.         if ((handle = novell_GDH (ingetfsid (nodeid))) != 255) {
  1018.         segregs.ds = get_ds();
  1019.         segregs.es = segregs.ds;
  1020.  
  1021.         sfireq.handle = handle;
  1022.         sfireq.pathlen = strlen (path+2);
  1023.         sfireq.len = 6 + sfireq.pathlen;
  1024.         sfirep.len = sizeof (sfirep) -2;
  1025.         strcpy (sfireq.path, path+2);
  1026.  
  1027.         novell_API(0xE3, &sfireq, &sfirep, regsin, ®sout, &segregs);
  1028.         if (regsout.h.al != 0)
  1029.             return NFSERR_IO;
  1030.  
  1031.         /* Set up the Set File Info request block */
  1032.         setfireq.handle = handle;
  1033.         setfireq.pathlen = strlen (path+2);
  1034.         setfireq.len = 4 + sizeof (struct _fileinfo) + sfireq.pathlen;
  1035.         setfirep.len = sizeof (setfirep) -2;
  1036.         strcpy (setfireq.path, path+2);
  1037.         setfireq.info = sfirep.info;
  1038.         setfireq.info.size = 0;
  1039.  
  1040.         /* Look up the Novell user ID */
  1041.         setfireq.info.ownerID = uid - uIDoffset;
  1042.         for (i = 0; i < uIDcount; i++)
  1043.           if (uIDmappings[i].unix_ID == uid + uIDoffset) {
  1044.               setfireq.info.ownerID = uIDmappings[i].Novell_ID;
  1045.               break;
  1046.           }
  1047.  
  1048.         /* Issue the Set File Information request */
  1049.         novell_API(0xE3, &setfireq, &setfirep, regsin, ®sout,
  1050.                &segregs);
  1051.         if (regsout.h.al != 0)
  1052.             return NFSERR_ACCES;
  1053.         }
  1054.     }
  1055. #endif /* NOVELL */
  1056.  
  1057.     /* Update cached file attributes */
  1058.     if (uid != -1)
  1059.       attr.na_uid = uid;
  1060.     if (gid != -1)
  1061.       attr.na_gid = gid;
  1062.     (void) inattrset (nodeid, &attr);
  1063.     return NFS_OK;
  1064.     }
  1065.     else
  1066.     return NFSERR_NOENT;
  1067. }
  1068.  
  1069. /*
  1070.  *  int file_unlink(char *name) --
  1071.  *       Removes named file.
  1072.  */
  1073. enum nfsstat file_unlink(name)
  1074.     char *name;
  1075. {
  1076.     u_long node;
  1077.     int    stat;
  1078.  
  1079.     /* Close the file if we still have a handle to it */
  1080.     if ((node = pntoin (name)) != -1)
  1081.     frdc_del (node);
  1082.  
  1083.     /* Reset file attributes */
  1084.     (void) setnormalfileattr(name);
  1085.  
  1086.     /* Call unlink library function to remove the file. */
  1087.     stat = unlink(name);
  1088. DBGPRT3 (nfserr, "unlink %s: stat = %d, len = %d", name, stat, strlen(name));
  1089.  
  1090.     /* Remove the inode associated with the file, if present. */
  1091.     if (stat == 0 && node != -1)
  1092.     inremnode (node);
  1093.     return (stat == 0) ? NFS_OK : puterrno (errno);
  1094. }
  1095.  
  1096.  
  1097. /*
  1098.  *  int file_rename(char *oldname, char *newname) --
  1099.  *       Renames a file
  1100.  */
  1101. enum nfsstat file_rename(oldname, newname)
  1102.     char *oldname, *newname;
  1103. {
  1104.     u_long node;
  1105.     int    err;
  1106.     struct stat buf;
  1107.     enum   nfsstat code;
  1108.  
  1109.     /* Close the file if we still have a handle to it */
  1110.     if ((node = pntoin (oldname)) != -1)
  1111.     frdc_del (node);
  1112.  
  1113.     /* Reset file attributes (e.g., read-only) */
  1114.     (void) setnormalfileattr(oldname);
  1115.  
  1116.     /* Validate the new filename */
  1117.     if ((code = validate_path (newname)) != NFS_OK)
  1118.       return (code);
  1119.  
  1120.     /* Delete destination file if present */
  1121.     if (stat (newname, &buf) == 0) {
  1122.     if (buf.st_mode & S_IFDIR)
  1123.       return NFSERR_ISDIR;
  1124.     if ((code = file_unlink (newname)) != NFS_OK)
  1125.       return code;
  1126.     }
  1127.  
  1128.     /* Call rename library function to rename the file. */
  1129.     err = rename(oldname,newname);
  1130.  
  1131.     /* Update the inode associated with the file, if present. */
  1132.     if (err == 0 && node != -1) {
  1133.     (void) inremnode (node);
  1134.     (void) addpathtodirtree(newname);
  1135.     }
  1136.     return (err == 0) ? NFS_OK : puterrno (errno);
  1137. }
  1138.  
  1139. /*
  1140.  *  enum nfsstat validate_path (char *name) --
  1141.  *       Validate a path name's syntax.  Returns 0 if OK.
  1142.  *       Modifies the path appropriately if NFS_TRUNCATENAMES is set.
  1143.  */
  1144. enum nfsstat validate_path (name)
  1145.      char *name;
  1146. {
  1147.     char *ptr, *ptr2, *strrchr(), *strchr();
  1148.     int i;
  1149.  
  1150.     if ((ptr = strrchr (name, '\\')) == (char *)NULL &&
  1151.     (ptr = strrchr (name, ':')) == (char *)NULL)
  1152.     ptr = name;
  1153.     else
  1154.         ptr++;
  1155.  
  1156.     /* Check validity of characters in final component */
  1157.     for (ptr2 = ptr; *ptr2; ) {
  1158.     if (*ptr2 <= ' ' || (*ptr2 & 0x80) || !inchvalid[*ptr2 - '!'])
  1159.       return NFSERR_INVAL;
  1160.     else
  1161.       ptr2++;
  1162.     }
  1163.  
  1164.     /* Verify there are no more than 8 chars before '.' */
  1165.     if ((i = strcspn (ptr, ".")) > 8) {
  1166.     if (!NFS_TRUNCATENAMES)
  1167.       return NFSERR_NAMETOOLONG;
  1168.     strcpy (ptr + 8, ptr + i);
  1169.     }
  1170.     if ((ptr2 = strchr (ptr, '.')) == (char *)NULL)
  1171.     return NFS_OK;
  1172.     else
  1173.         ptr2++;
  1174.     ptr = ptr2;
  1175.     if (strlen (ptr) > 3) {
  1176.     if (!NFS_TRUNCATENAMES)
  1177.       return NFSERR_NAMETOOLONG;
  1178.     ptr[3] = '\0';
  1179.     }
  1180.     return NFS_OK;
  1181. }
  1182.  
  1183.